package genetic2;

import java.util.*;

/**
 *
 * @author Manolescu Razvan
 */

public class Population {
    
    Individual[] inds;
    static Individual best;
    int scoreB = 0;
    static int curGen , changeCounter = 0;
    private Map<String, List<ColumnStatistics>> colStats;
    
    public Population(final Map<String, List<ColumnStatistics>> colStats){       
        inds = new Individual[GeneticParameters.NUMCHILDREN];
        curGen = 1;
        
        this.colStats = colStats;
        
        for(int i=0; i< GeneticParameters.NUMCHILDREN; i++)
            inds[i] = new Individual(colStats, GeneticParameters.maxSizeInKb);       
    }
    
    public void newGeneration(){
        ArrayList<Individual> top = new ArrayList<Individual>();
        TreeSet<Individual> ts = new TreeSet<Individual>( );
        int i,j,h;
        int retLen = (int)( (double) GeneticParameters.NUMCHILDREN * 
                GeneticParameters.RETAIN /(double)GeneticParameters.PERCENTOF );
                
        Random r = new Random();
        
        for(i=0; i< GeneticParameters.NUMCHILDREN; i++){         
            ts.add(inds[i]);
        } 
    
        // best fitting
        for(i=0; i< retLen; i++){
            Individual ind = ts.first(); 
            top.add(ind);
        }
              
        updateBest(top.get(0));

        // random selection
        for(i=retLen; i< GeneticParameters.NUMCHILDREN; i++)
            if(r.nextInt(GeneticParameters.PERCENTOF) < GeneticParameters.RANDSEL){
                if( GeneticParameters.DEBUG && GeneticParameters.PRINTEVO)
                    System.out.println("Random selection "+i);
                top.add(inds[i]);
                ++retLen;
            }

         for(i=0; i<retLen; i++){
             inds[i] = top.get(i);
         }
         
         h = retLen;
         
         // crossover
         for(i=0; i<retLen-1 && h< GeneticParameters.NUMCHILDREN; i++)
            for( j = i+1; j<retLen && h< GeneticParameters.NUMCHILDREN ; j++){
                inds[h].crossover( inds[i] , inds[j], GeneticParameters.maxSizeInKb);
                ++h;
            }

         // mutation
         for(i=0; i< GeneticParameters.NUMCHILDREN ; i++)
            if(r.nextInt(GeneticParameters.PERCENTOF) < GeneticParameters.MUTATE){
                if( GeneticParameters.DEBUG && GeneticParameters.PRINTEVO)
                        System.out.println("Mutation "+i);
                if( inds[i] != null ){
                   inds[i].mutate(GeneticParameters.maxSizeInKb) ;
                }
            }
        
         // topup mutation
        for(i=retLen; i< GeneticParameters.NUMCHILDREN ; i++)
            if(r.nextInt(GeneticParameters.PERCENTOF) < GeneticParameters.MUTATETOPUP){
                if( GeneticParameters.DEBUG && GeneticParameters.PRINTEVO)
                        System.out.println("Mutation TopUp "+i);
                if( inds[i] != null ){
                   inds[i] = new Individual(colStats, GeneticParameters.maxSizeInKb);
                }
            }
         
         top.clear();
         ts.clear();
        
         ++curGen;       
         ++changeCounter;
         top = null;
         ts = null;
         System.gc();
    }
    
    @Override
    public String toString(){
        int i;
        final StringBuffer sb = new StringBuffer("\n- Generation [");
        sb.append(curGen); 
        sb.append("]-------------------------------------------------------\n");
        
        if( GeneticParameters.PRINTCHILDREN )
            for(i=0; i<GeneticParameters.NUMCHILDREN; i++){
                sb.append(inds[i].toString());
           }
        
        return sb.toString();      
    }
    
    public void updateBest( Individual i ){  
        final int scoreI = (int)(i.getFitness()*1000);
        if( scoreI > scoreB ){
            scoreB = scoreI;
            best = (Individual) i.clone();
            changeCounter = 0;
        }
    }
}
